home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / filesyst / dosfs / dmsdosfs.000 / dmsdosfs / dmsdosfs-0.6.9b / dmsdos_lfn.c < prev    next >
C/C++ Source or Header  |  1996-07-31  |  12KB  |  451 lines

  1. /*
  2. dmsdos_lfn.c
  3.  
  4. long filename support for dmsdos filesystem
  5.  
  6. ******************************************************************************
  7. DMSDOS (Doublespace/Drivespace compressed MSDOS filesystem) for Linux
  8. written 1995,1996 by Frank Gockel
  9.  
  10.     (C) Copyright 1995,1996 by Frank Gockel
  11.  
  12. Some code of the dmsdos filesystem has been copied from the msdos filesystem
  13. so there are the following additional copyrights:
  14.  
  15.     (C) Copyright 1992,1993 by Werner Almesberger (msdos filesystem)
  16.     (C) Copyright 1994,1995 by Jacques Gelinas (mmap code)
  17.     (C) Copyright 1992-1995 by Linus Torvalds
  18.  
  19. The DMSDOS filesystem was inspired by the THS filesystem (a simple doublespace
  20. DS-0-2 compressed read-only filesystem) written 1994 by Thomas Scheuermann.
  21.  
  22. The DMSDOS filesystem is distributed under the Gnu General Public Licence.
  23. See file COPYING for details.
  24. ******************************************************************************
  25.  
  26. */
  27.  
  28. #include<linux/fs.h>
  29. #include <linux/errno.h>
  30. #include <linux/string.h>
  31. #include <linux/kernel.h>
  32. #include<linux/msdos_fs.h>
  33. #include<linux/dmsdos_fs.h>
  34.  
  35. extern Dblsb dblsb[];
  36.  
  37. /* should be enough */
  38. #define MAX_LFN_DIRENTRIES 25
  39.  
  40. unsigned char checksum(unsigned char * buf)
  41. { int i;
  42.   unsigned char sum=0;
  43.   
  44.   for(i=0;i<11;++i)
  45.   { if(sum&1)sum=sum/2+0x80;
  46.     else sum/=2;
  47.     sum+=buf[i];
  48.   }
  49.   return sum;
  50. }
  51.  
  52. /* reads lfn direntry: real direntry in buf, filename in longname
  53.    if it is a short name, longname is setup right (lower case)
  54.    returns ino of short name/error code
  55.    if lfn_inos!=NULL: returns list of inos in reverse order (first=short name)
  56. */
  57.  
  58. int read_lfn_direntry(struct super_block*sb,int dirstartclust,int cvfnr,
  59.                        int entrynr, char*longname, unsigned char*buf,
  60.                        int * lfn_inos)
  61. { int ino;
  62.   unsigned char buf2[32];
  63.   char *name;
  64.   int islong;
  65.   int order,i;
  66.   unsigned char checks;
  67.   
  68.   /*printk("DMSDOS: read_lfn_direntry begin\n");*/
  69.   
  70.   /* initialize with zeros -- for safety */
  71.   if(lfn_inos)for(i=0;i<MAX_LFN_DIRENTRIES;++i)lfn_inos[i]=0;
  72.    
  73.   islong=dblsb[cvfnr].s_support_lfn&1;
  74.   order=0;
  75.   name=longname;
  76.   *name='\0';
  77.   
  78.   ino=read_dbl_direntry(sb,dirstartclust,cvfnr,entrynr,buf);
  79.   if(ino<0)return ino;
  80.   if(lfn_inos)lfn_inos[order]=ino;
  81.   if(buf[0]==0||buf[0]==0xe5||(buf[11]&ATTR_VOLUME)!=0)return ino;
  82.   
  83.   checks=checksum(buf);
  84.   
  85.   if(entrynr==0)islong=0; /* first can't be long, but does never enter loop */
  86.   while(entrynr>0&&order<0x3f&&islong!=0)
  87.   { --entrynr;
  88.     ++order;
  89.     i=read_dbl_direntry(sb,dirstartclust,cvfnr,entrynr,buf2);
  90.     if(lfn_inos)lfn_inos[order]=i;
  91.     if(checks!=buf2[13]||(buf2[0]&0x3f)!=order||buf2[11]!=0xf)
  92.     { /* if((buf2[0]&0x3f)==order&&buf2[11]==0xf)
  93.          printk("DMSDOS: wrong checksum: formula=%d is=%d\n",checks,buf2[13]);
  94.       */
  95.       islong=0;
  96.       if(lfn_inos)lfn_inos[1]=0; /* cut lfn_inos array (rest after a zero is iqnored) */
  97.       break;
  98.     }
  99.     for(i=0;i<5;++i)
  100.     { if(buf2[1+2*i]==255&&buf2[2+2*i]==255)break; 
  101.       *(name++)=buf2[1+2*i];
  102.     }
  103.     for(i=0;i<6;++i)
  104.     { if(buf2[14+2*i]==255&&buf2[15+2*i]==255)break;
  105.       *(name++)=buf2[14+2*i];
  106.     }
  107.     for(i=0;i<2;++i)
  108.     { if(buf2[28+2*i]==255&&buf2[29+2*i]==255)break;
  109.       *(name++)=buf2[28+2*i];
  110.     }
  111.     if(buf2[0]&0x40)break;
  112.   }
  113.   *name='\0';
  114.   
  115.   if(islong==0)
  116.   { name=longname;
  117.     for(i=0;i<8;++i)
  118.     { if(buf[i]==' ')break;
  119.       if( (dblsb[cvfnr].s_support_lfn&8)!=0 &&buf[i]>='A'&&buf[i]<='Z')
  120.            *(name++)=buf[i]+32;
  121.       else *(name++)=buf[i];
  122.     }
  123.     if(buf[8]!=' ')*(name++)='.';
  124.     for(i=8;i<11;++i)
  125.     { if(buf[i]==' ')break;
  126.       if( (dblsb[cvfnr].s_support_lfn&8)!=0 &&buf[i]>='A'&&buf[i]<='Z')
  127.            *(name++)=buf[i]+32;
  128.       else *(name++)=buf[i];
  129.     }
  130.     *name='\0';                                   
  131.   }
  132.   
  133.   /*printk("DMSDOS: read_lfn_direntry: name found %s\n",longname);*/
  134.   return ino; 
  135.  
  136. /* returns ino */
  137. int scan_dbl_dir_4_lfn(struct super_block*sb, int dirstartclust,
  138.                        const char*tofind1,int len,int cvfnr,int*lfn_inos)
  139. { int entrynr,i,ppos;
  140.   char name[257];
  141.   unsigned char buf[32];
  142.   int ino;
  143.   char tofind2[257];
  144.   const char * tofind;
  145.  
  146.   /*printk("DMSDOS: scan_dbl_dir_4_lfn: searching for %s\n",tofind);*/
  147.   
  148.   if((dblsb[cvfnr].s_support_lfn&1)==0)
  149.   { /* case should not be significant ... 
  150.        so convert upper case in tofind to lower case
  151.     */
  152.     for(i=0;i<len;++i)
  153.     { if(tofind1[i]>='A'&&tofind1[i]<='Z')tofind2[i]=tofind1[i]-'A'+'a';
  154.       else tofind2[i]=tofind1[i];
  155.     }
  156.     
  157.     /* now match the 8.3 convention */
  158.     
  159.     /* find first '.' */
  160.     ppos=0;
  161.     for(i=0;i<len;++i)
  162.     { if(tofind2[i]=='.')ppos=i;
  163.     }
  164.     if(ppos==0&&len>8)len=8;
  165.     if(ppos>0&&ppos<=8&&len-ppos>4)len=ppos+4;
  166.     if(ppos>8)
  167.          { tofind2[8]='.';
  168.            if(len>ppos+1)tofind2[9]=tofind2[ppos+1];
  169.            if(len>ppos+2)tofind2[10]=tofind2[ppos+2];
  170.            if(len>ppos+3)tofind2[11]=tofind2[ppos+3];
  171.            /* subtract number of characters that have been cut off
  172.               before the '.' */
  173.            len -=(ppos-8);
  174.            /* limit total length */
  175.            if(len>12)len=12;  /* incl. '.' */
  176.          }
  177.     tofind=tofind2;
  178.   }
  179.   else tofind=tofind1;
  180.   
  181.   entrynr=0;
  182.   do
  183.   { ino=read_lfn_direntry(sb,dirstartclust,cvfnr,entrynr,name,buf,lfn_inos);
  184.     if(ino<0)return ino;
  185.     if((buf[11]&ATTR_VOLUME)==0&&buf[0]!=0xe5)
  186.     { /*if(strncmp(name,tofind,len)==0)return ino;*/
  187.       /*if(strcmp(name,tofind)==0)return ino;*/
  188.       if(strlen(name)==len&&strncmp(name,tofind,len)==0)return ino;
  189.     }
  190.     ++entrynr;
  191.   }
  192.   while(buf[0]!=0);
  193.   return -ENOENT;
  194. }
  195.  
  196. int dmsdos_get_lfn_entry(struct inode *dir, loff_t *pos,unsigned char * buf,
  197.                          char*longname)
  198. {
  199.   int entrynr;
  200.   int ino;
  201.   int clust;
  202.   int cvfnr;
  203.                              
  204.   entrynr = (*pos)>>5;
  205.   /*printk("DMSDOS: get_lfn_entry nr %d\n",entrynr);*/
  206.   *pos += 32;
  207.   if((cvfnr=dbltest(dir))!=0)cvfnr=(cvfnr>>DMSDOS_CVFNR_BITS)-1;
  208.   else cvfnr=(dir->i_ino>>DMSDOS_CVFNR_BITS)-1;
  209.   clust=MSDOS_I(dir)->i_start;/*dbl_inode2startcluster(dir);*/
  210.   ino=read_lfn_direntry(dir->i_sb,clust,cvfnr,entrynr,longname,buf,NULL);
  211.   /* break on zero entry */
  212.   if(buf[0]==0)return -ENOENT;
  213.   /*printk("DMSDOS: dmsdos_get_lfn_entry: found %s\n",longname);*/
  214.   return ino;
  215. }
  216.  
  217. /* returns 0 if okay */
  218. int remove_lfn_entry(struct super_block*sb, int dirstartclust,
  219.                      const char*tofind, int len, int cvfnr)
  220. { int lfn_inos[MAX_LFN_DIRENTRIES];
  221.   int i;
  222.   struct buffer_head*bh;
  223.   int dblsec,offs;
  224.   
  225.   i=scan_dbl_dir_4_lfn(sb,dirstartclust,tofind,len,cvfnr,lfn_inos);
  226.   if(i<0)return i;
  227.   
  228.   i=0;
  229.   while(lfn_inos[i]!=0&&i<MAX_LFN_DIRENTRIES)
  230.   {  dblsec=(lfn_inos[i]&DMSDOS_ORIGINO_MASK)>>4;
  231.      offs=(lfn_inos[i]&0xf)<<5;       
  232.      bh=read_dbl_sector(sb,dblsec,cvfnr);
  233.      if(bh==NULL)return -EIO;
  234.      if(i>0&&bh->b_data[offs+11]!=0xf) /* oh oh -- this isn't a long name */
  235.      { bh_free(sb,bh);
  236.        break;
  237.      }
  238.      bh->b_data[offs]=0xe5;
  239.      bh->b_data[offs+11]&=~ATTR_VOLUME;
  240.      bh_dirty(sb,bh);
  241.      bh_free(sb,bh);
  242.      ++i;
  243.   }
  244.   
  245.   return 0;
  246. }
  247.  
  248. int must_be_long(const char*name,int len,int*p_ppos,int cvn)
  249. { int ppos;
  250.   int i;
  251.  
  252.   /* check point position */
  253.  
  254.   ppos=-1;
  255.   for(i=0;i<len;++i)
  256.   { if(name[i]=='.')
  257.     { if(ppos<0)ppos=i;
  258.       else
  259.       { if(p_ppos)*p_ppos=ppos;
  260.         return 1;
  261.       }
  262.     }
  263.   }
  264.   
  265.   if(p_ppos)*p_ppos=ppos;
  266.   if(ppos==-1&&len>8)return 1;
  267.   if(ppos==0||ppos>8)return 1;
  268.   if(len>12)return 1;
  269.   if(ppos==len)return 1;
  270.   if(ppos>0&&len-ppos>4) return 1;
  271.   
  272.   /* check for undesired characters */
  273.   
  274.   for(i=0;i<len;++i)
  275.   { if(name[i]<=32)return 1;
  276.     if(name[i]==34||name[i]==92)return 1;
  277.     if(name[i]>=42&&name[i]<=44)return 1;
  278.     if(name[i]>=59&&name[i]<=63)return 1;
  279.     if(name[i]==124||name[i]>=126)return 1;
  280.     if(name[i]>='a'&&name[i]<='z'&&cvn==0)return 1;
  281.     if(name[i]>='A'&&name[i]<='Z'&&cvn!=0)return 1;
  282.   }
  283.   
  284.   return 0;
  285. }
  286.  
  287. /* must be called locked */
  288. /* longname must not already exist (no check here) */
  289. /* returns ino of (incomplete) short entry */
  290. int create_lfn_entry(struct super_block*sb, int dirstartclust,
  291.                      const char*longname, int len, int cvfnr)
  292. {  /*printk("DMSDOS: create_lfn_entry: Not yet implemented, sorry.\n");
  293.      return -EIO;*/
  294.      
  295.    int ilong;
  296.    char shortname[12];
  297.    int i,j;
  298.    int ppos,spos,pos;
  299.    char numstr[10];
  300.    int versuch;
  301.    int lnumstr;
  302.    int req;
  303.    int lfn_inos[MAX_LFN_DIRENTRIES];
  304.    int dblsec;
  305.    int offs;
  306.    struct buffer_head * bh;
  307.    int checks;
  308.    int ino;
  309.    
  310.    if(len>255)return -EINVAL;
  311.    
  312.    strcpy(shortname,"           ");
  313.           /*         12345678EXT   */
  314.    
  315.    ilong=(dblsb[cvfnr].s_support_lfn&16) ? 1 :
  316.          must_be_long(longname,len,&ppos,dblsb[cvfnr].s_support_lfn&8);
  317.    
  318.    if(ilong)strcpy(shortname,"~~~~~~~~   ");
  319.            /*                 12345678EXT       */
  320.            
  321.    if(ppos<=0)ppos=len;
  322.    
  323.    for(i=0;i<ppos&&i<8;++i)
  324.    { shortname[i]=longname[i];
  325.      if(longname[i]<=32)shortname[i]='~';
  326.      if(longname[i]==34||longname[i]==92)shortname[i]='~';
  327.      if(longname[i]>=42&&longname[i]<=44)shortname[i]='~';
  328.      if(longname[i]>=59&&longname[i]<=63)shortname[i]='~';
  329.      if(longname[i]>=97&&longname[i]<=122)shortname[i]=longname[i]-32;
  330.      if(longname[i]==124||longname[i]>=126)shortname[i]='~';
  331.    }
  332.    
  333.    if(ppos<len)
  334.    { for(i=ppos+1,j=8;i<len&&j<11;++i,++j)
  335.      { shortname[j]=longname[i];
  336.        if(longname[i]<=32)shortname[j]='~';
  337.        if(longname[i]==34||longname[i]==92)shortname[j]='~';
  338.        if(longname[i]>=42&&longname[i]<=44)shortname[j]='~';
  339.        if(longname[i]>=59&&longname[i]<=63)shortname[j]='~';
  340.        if(longname[i]>=97&&longname[i]<=122)shortname[j]=longname[i]-32;
  341.        if(longname[i]==124||longname[i]>=126)shortname[j]='~';
  342.      }
  343.    }
  344.    
  345.    if(ilong)
  346.    {
  347.      versuch=0;
  348.    
  349.      do
  350.      { ++versuch;
  351.        sprintf(numstr,"~%d",versuch);
  352.        lnumstr=strlen(numstr);
  353.        spos=8-lnumstr;
  354.        for(i=0;i<lnumstr;++i)shortname[i+spos]=numstr[i];
  355.      }
  356.      while(scan_dbl_dir_4_filename(sb,dirstartclust,shortname,11,cvfnr)>0);
  357.    }
  358.  
  359.    /* okay, everything is set up now */
  360.    
  361.    if(!ilong)req=1;
  362.    else req=2+((len-1)/13);
  363.    
  364.    ino=scan_dbl_dir_4_n_empty(sb,dirstartclust,cvfnr,req,lfn_inos);
  365.    if(ino<0)return ino;
  366.    
  367.    /* now write the short entry */
  368.    dblsec=(ino&DMSDOS_ORIGINO_MASK)>>4;
  369.    offs=(ino&0xf)<<5;
  370.    bh=read_dbl_sector(sb,dblsec,cvfnr);
  371.    if(bh==NULL)return -EIO;
  372.    bh->b_data[offs+11]=ATTR_VOLUME; /* ignore this entry as it is incomplete */
  373.    for(i=0;i<11;++i)bh->b_data[offs+i]=shortname[i];
  374.    bh_dirty(sb,bh);
  375.    bh_free(sb,bh);
  376.    
  377.    if(!ilong)return ino;
  378.    
  379.    checks=checksum(shortname);
  380.    
  381.    pos=0;
  382.    
  383.    for(j=1;j<req;++j)
  384.    {  dblsec=(lfn_inos[j]&DMSDOS_ORIGINO_MASK)>>4;
  385.       offs=(lfn_inos[j]&0xf)<<5;
  386.       bh=read_dbl_sector(sb,dblsec,cvfnr);
  387.       if(bh==NULL)return -EIO;
  388.       
  389.       bh->b_data[offs]=(j==req-1)?j|0x40:j;
  390.       bh->b_data[offs+11]=0xf;
  391.       bh->b_data[offs+13]=checks;
  392.       bh->b_data[offs+26]=0;
  393.       bh->b_data[offs+27]=0;
  394.       
  395.       for(i=0;i<5;++i)
  396.       {  if(pos<len)
  397.          { bh->b_data[offs+2+2*i]=0;
  398.            bh->b_data[offs+1+2*i]=longname[pos];
  399.          }
  400.          else if(pos==len)
  401.          { bh->b_data[offs+1+2*i]=0;
  402.            bh->b_data[offs+2+2*i]=0;
  403.          }
  404.          else
  405.          { bh->b_data[offs+1+2*i]=255;
  406.            bh->b_data[offs+2+2*i]=255;
  407.          }
  408.          ++pos;
  409.       }
  410.  
  411.       for(i=0;i<6;++i)
  412.       {  if(pos<len)
  413.          { bh->b_data[offs+15+2*i]=0;
  414.            bh->b_data[offs+14+2*i]=longname[pos];
  415.          }
  416.          else if(pos==len)
  417.          { bh->b_data[offs+14+2*i]=0;
  418.            bh->b_data[offs+15+2*i]=0;
  419.          }
  420.          else
  421.          { bh->b_data[offs+14+2*i]=255;
  422.            bh->b_data[offs+15+2*i]=255;
  423.          }
  424.          ++pos;
  425.       }
  426.       
  427.       for(i=0;i<2;++i)
  428.       {  if(pos<len)
  429.          { bh->b_data[offs+29+2*i]=0;
  430.            bh->b_data[offs+28+2*i]=longname[pos];
  431.          }
  432.          else if(pos==len)
  433.          { bh->b_data[offs+28+2*i]=0;
  434.            bh->b_data[offs+29+2*i]=0;
  435.          }
  436.          else
  437.          { bh->b_data[offs+28+2*i]=255;
  438.            bh->b_data[offs+29+2*i]=255;
  439.          }
  440.          ++pos;
  441.       }
  442.                
  443.       bh_dirty(sb,bh);
  444.       bh_free(sb,bh);
  445.                         
  446.    } 
  447.    
  448.    return ino;                                  
  449. }
  450.